package com.bookshop.dao;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class BaseDao {
    private String driver = "com.mysql.cj.jdbc.Driver";
    private String url = "jdbc:mysql://localhost:3306/bookshopplus?serverTimezone=Asia/Shanghai";
    private String user = "root";
    private String password = "root";

    protected Connection conn = null;

    /**
     * 获取数据库连接对象
     *
     * @return
     */
    public Connection getConnection() {
        try {
            //加载驱动
            Class.forName(driver);
            //建立连接
            conn = DriverManager.getConnection(url, user, password);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭资源
     *
     * @param conn 连接对象
     * @param stmt 执行对象
     * @param rs   结果集
     */
    public void closeAll(Connection conn, Statement stmt, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (stmt != null) {
            try {
                stmt.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 数据库 增 删 改 操作方法
     *
     * @param sql    sql语句
     * @param params 可选参数数组
     * @return 受影响的行数 int,如果执行错误则返回 -1,失败则返回 0;
     */
    public int update(String sql, Object... params) {
        int row = 0;//默认受影响行数值为0
        PreparedStatement stmt = null;//执行对象
        try {
            getConnection();//建立连接
            //实例化执行对象
            stmt = this.conn.prepareStatement(sql);
            //设置参数
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            //开始执行并接收执行结果
            row = stmt.executeUpdate();//增 删 改
        } catch (Exception e) {
            row = -1;
        } finally {
            //关闭资源
            this.closeAll(conn, stmt, null);
        }
        return row;
    }


    /**
     * 数据库 查询 操作方法
     *
     * @param sql    sql语句
     * @param params 可选参数数组
     * @return 返回ResultSet结果集
     */
    public ResultSet query(String sql, Object... params) {
        PreparedStatement stmt = null;//执行对象
        ResultSet rs = null;//结果集
        try {
            this.getConnection();//建立连接
            //实例化执行对象
            stmt = this.conn.prepareStatement(sql);
            //设置参数
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            //开始执行并接收执行结果
            rs = stmt.executeQuery();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rs;
    }


    /**
     * 查询集合数据列表操作方法（反射实现）
     *
     * @param sql  sql语句
     * @param cls  对象
     * @param params 可选参数数组
     * @return 返回 List
     */
    public List queryList(String sql, Class cls, Object... params) {
        List list = new ArrayList();
        PreparedStatement stmt = null;//执行对象
        ResultSet rs = null;//结果集
        try {
            conn = this.getConnection();//建立连接
            //实例化执行对象
            stmt = this.conn.prepareStatement(sql);
            //设置参数
            if (params != null && params.length > 0) {
                for (int i = 0; i < params.length; i++) {
                    stmt.setObject(i + 1, params[i]);
                }
            }
            //开始执行并接收执行结果
            rs = stmt.executeQuery();
            // 获取结果集的元数据对象（查询到的字段数量以及查询了哪些字段）
            ResultSetMetaData resultSetMetaData = rs.getMetaData();
            // 获取查询的字段数量
            int columnCount = resultSetMetaData.getColumnCount();
            // 遍历分析结果集
            while (rs.next()) {
                // 实例化对象
                Object object = cls.newInstance();
                // 遍历查询的字段数量，得到数据库中查询的每一个列名
                for (int i = 1; i <= columnCount; i++) {
                    // 得到查询的每一个列名
                    // getColumnLabel()：获取列名或别名 getColumnName()：获取列名
                    String columnName = resultSetMetaData.getColumnLabel(i);
                    // 通过反射，使用列名得到对应的field对象
                    Field field = cls.getDeclaredField(columnName);
                    // 拼接set方法，得到字符串
                    String setMethod = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1);
                    // 通过反射，将set方法字符串反射成类中对应的set方法
                    Method method = cls.getDeclaredMethod(setMethod, field.getType());
                    // 得到查询的每一个字段对应的值
                    Object value = rs.getObject(columnName);
                    // 通过invoke方法调用set方法
                    method.invoke(object, value);
                }
                list.add(object);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            this.closeAll(conn, stmt, rs);
        }
        return list;
    }

    /**
     * 查询单个对象操作方法
     * @param sql  sql语句
     * @param cls  对象
     * @param params 可选参数数组
     * @return
     */
    public Object queryObject(String sql, Class cls, Object... params) {
         Object object=null;
         List list=queryList(sql,cls,params);
         if (list!=null&&list.size()>0){
             object=list.get(0);
         }
         return object;
    }
}
